// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
// http://www.zhengzhong.net/
//
// $Id: navigate_dom_tree.hpp 318 2009-03-02 14:03:21Z heavyzheng $
//

#ifndef ZZHENG_EXAMPLE_NAVIGATE_DOM_TREE_HPP_20080806__
#define ZZHENG_EXAMPLE_NAVIGATE_DOM_TREE_HPP_20080806__

#include <zzheng/xml/dom.hpp>

#include <cassert>
#include <exception>
#include <memory>
#include <string>
#include <iostream>

namespace zzheng {
namespace example {

    inline
    void navigate_dom_tree(const xml::dom::element& elem, unsigned int indent) {

        std::cout << std::string(indent, ' ')
                  << "element: " << elem.name()
                  << ( elem.uri().empty() ? std::string() : " (xmlns=" + elem.uri() + ")" )
                  << std::endl;

        const xml::dom::attribute_map& attrs = elem.attributes();
        typedef xml::dom::const_attribute_iterator const_attribute_iterator;
        for (const_attribute_iterator i = attrs.begin(); i != attrs.end(); ++i) {
            std::cout << std::string(indent, ' ')
                      << "@" << i->name() << " = " << i->value()
                      << ( i->uri().empty() ? std::string() : " (xmlns=" + i->uri() + ")" )
                      << std::endl;
        }

        const xml::dom::child_node_list& children = elem.children();
        typedef xml::dom::const_child_iterator const_child_iterator;
        for (const_child_iterator i = children.begin(); i != children.end(); ++i) {
            if (i->type() == xml::dom::element_node) {
                xml::dom::const_element_ptr child = xml::dom::dynamic_node_cast<
                                                    const xml::dom::element
                                                    >(i.ptr());
                if (child != 0) {
                    navigate_dom_tree(*child, indent + 2);
                } else {
                    std::cout << std::string(indent + 2, ' ')
                              << "error: child element should not be null."
                              << std::endl;
                }
            } else if (i->type() == xml::dom::text_node) {
                std::cout << std::string(indent + 2, ' ')
                          << "text: " << i->content()
                          << std::endl;
            } else {
                std::cout << std::string(indent + 2, ' ')
                          << "error: unknown child node type id " << i->type()
                          << std::endl;
            }
        }
    }

    inline
    int navigate_dom_tree(const char* xml_str) {
        try {
            // Parse the XML file into a document.
            xml::dom::parser parser;
            std::auto_ptr<xml::dom::document> doc(parser.parse_string(xml_str));
            assert(doc.get() != 0);

            xml::dom::element_ptr root = doc->root();
            navigate_dom_tree(*root, 0);
            return 0;

        } catch (const xml::dom::dom_error& ex) {
            std::cerr << "om_error: " << ex.what() << std::endl;
            return 1;
        } catch (const std::exception& ex) {
            std::cerr << "std::exception: " << ex.what() << std::endl;
            return 1;
        } catch (...) {
            std::cerr << "unknown error." << std::endl;
            return 1;
        }
    }


} // namespace zzheng::example
} // namespace zzheng

#endif // ZZHENG_EXAMPLE_NAVIGATE_DOM_TREE_HPP_20080806__



